package com.wugh.fast.kernel.util.recursive;

import com.wugh.fast.kernel.util.exception.FastRecursiveException;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.BinaryOperator;
import java.util.function.Function;

/**
 * 说明: 默认的递归处理
 *
 * @author wugh
 * @date 2019-12-11 15:31
 */
public class DefaultRecursive<T, R> implements Recursive<T, R> {
    //目前不开放设置
    protected int maxTime = 1000;
    protected AtomicInteger count = new AtomicInteger(0);
    /**
     * 递归函数
     */
    protected Function<T, R> function;
    /**
     * 递归判断条件
     */
    protected BiPredicate<T, R> test = (t, r) -> false;

    /**
     * 合并处理
     */
    protected BiFunction<T, R, T> map = (t, r) -> null;
    /**
     * 合并的第一个数据,如果为null.则合并方法,第一次不会执行
     */
    protected R identity;
    /**
     * 合并函数
     */
    protected BinaryOperator<R> reduce = (t, r) -> r;

    @Override
    public Recursive<T, R> function(Function<T, R> function) {
        //扩展方法,增加计数
        this.function = t -> {
            if (this.count.getAndIncrement() >= this.maxTime) {
                //次数到达1000,肯定进入死循环
                throw new FastRecursiveException(this.count.get());
            }
            return function.apply(t);
        };
        return this;
    }

    @Override
    public Recursive<T, R> test(BiPredicate<T, R> predicate) {
        this.test = predicate;
        return this;
    }

    @Override
    public Recursive<T, R> map(BiFunction<T, R, T> map) {
        this.map = map;
        return this;
    }

    @Override
    public Recursive<T, R> reduce(BinaryOperator<R> reduce) {
        this.reduce = reduce;
        this.identity = null;
        return this;
    }

    @Override
    public Recursive<T, R> reduce(R identity, BinaryOperator<R> reduce) {
        this.reduce = reduce;
        this.identity = identity;
        return this;
    }

    @Override
    public R exec(T value) {
        return execBase(value, this.identity, this.function, this.test, this.map, this.reduce);
    }

    /**
     * 递归处理
     *
     * @param current   当前执行的值
     * @param prev      上次处理的结果
     * @param func      递归执行方法
     * @param predicate 判断是否进入下一次递归
     * @param mapFunc   下一次循环的入参处理方法
     * @param reduce    结果合并,会传入之前的结果和当前的结果(注意第一次执行递归方法不会执行)
     * @param <T>       入参泛型
     * @param <R>       结果泛型
     * @return 返回递归结果
     */
    protected static <T, R> R execBase(T current, R prev, Function<T, R> func, BiPredicate<T, R> predicate, BiFunction<T, R, T> mapFunc, BinaryOperator<R> reduce) {
        //函数处理结果
        R ret = func.apply(current);
        //结果合并
        R cur = prev == null ? ret : reduce.apply(prev, ret);
        if (predicate.test(current, ret)) {
            //进入下一次循环,构件新的入参
            T v = mapFunc.apply(current, ret);
            return execBase(v, cur, func, predicate, mapFunc, reduce);
        }
        //没有进入下次循环,则返回合并的最终结果即可
        return cur;
    }
}
